//
//  VideoView.m
//  openEye
//
//  Created by 徐悟源 on 16/4/1.
//  Copyright © 2016年 Wuyuan. All rights reserved.
//

#import "VideoView.h"
#import "WYSilder.h"
#import <MediaPlayer/MediaPlayer.h>
#import <AVFoundation/AVFoundation.h>

@interface VideoView()

@property (nonatomic , strong) AVPlayerItem *playerItem;

@property (nonatomic , strong) AVPlayerLayer *playerLayer;

@property (nonatomic , strong) UIActivityIndicatorView *activityIndicator;

@property (nonatomic , strong) id playbackObserver;

@property (nonatomic , assign) BOOL isViewShowing;
@property (nonatomic , assign) BOOL isPlaying;

/** 整页蒙板 */
@property (nonatomic , strong) UIView *overHudView;

/** 工具条蒙板 */
@property (nonatomic , strong) UIView *toolsHUDView;

/** 页面回退label */
@property (nonatomic , strong) UIButton *pageBackButton;

/** 文件名Label */
@property (nonatomic , strong) UILabel *titleLabel;

/** play/pause按钮*/
@property (nonatomic , strong) UIButton *playPauseButton;

/** 播放器的蒙板 */
@property (nonatomic , strong) UIView *playerHudView;

/** 播放条滑块 */
@property (nonatomic , strong) UISlider *progressBar;

/** 缓冲进度条 */
@property (nonatomic , strong) UIProgressView *loadedTimeView;

/** 已播放时间 */
@property (nonatomic , strong) UILabel *playBackTime;

/** 视频总时长 */
@property (nonatomic , strong) UILabel *playBackTotalTime;

@end

@implementation VideoView

#pragma mark - AVPlayerLayer Setup

+ (Class)layerClass
{
    return [AVPlayerLayer class];
}

- (AVPlayer *)player
{
    return [(AVPlayerLayer *)[self layer] player];
}

- (void)setPlayer:(AVPlayer *)player
{
    [(AVPlayerLayer *)[self layer] setPlayer:player];
}

- (void)setVideoFillMode:(NSString *)fillMode
{
    AVPlayerLayer *playLayer = (AVPlayerLayer *)[self layer];
    playLayer.videoGravity = fillMode;
}

- (void)layoutSubviews
{
    [super layoutSubviews];

    
    if(self.shouldShowHideParentNavigationBar)
    {
#warning 下面写完了再写这
        [self initializePlayerAtFrame];
        [self setupConstraints];

    }
}

#pragma mark - 界面初始化
- (instancetype)initWithFrame:(CGRect)frame playerItem:(AVPlayerItem *)playerItem
{
    self = [super initWithFrame:frame];
    if(self)
    {
        [self setupPlayerWithPlayerItem:playerItem forFrame:frame];
    }
    
    return self;
}

- (instancetype)initWithFrame:(CGRect)frame contentURL:(NSURL *)contentURL
{
    self = [super initWithFrame:frame];
    if(self)
    {
        [self setupPlayerWithURL:contentURL forFrame:frame];
    }
    
    return self;
}

#pragma mark - 播放器方法初始化
- (void)setupPlayerWithURL:(NSURL *)url forFrame:(CGRect )frame
{
    if(self.contentURL)
    {
        self.contentURL = nil;
    }
    
    AVPlayerItem *playItem = [AVPlayerItem playerItemWithURL:url];
    [self setupPlayerWithPlayerItem:playItem forFrame:frame];
    self.contentURL = url;
}

- (void)setupPlayerWithPlayerItem:(AVPlayerItem *)playItem forFrame:(CGRect)frame
{
    [self unregisterObservers];
    
    if(self.moviePlayer)
    {
        self.moviePlayer = nil;
    }
    
    if(self.playerLayer)
    {
        self.playerLayer = nil;
    }
    
    if(self.playerItem)
    {
        self.playerItem = nil;
    }
    
    _playerItem = playItem;
    
    self.moviePlayer = [AVPlayer playerWithPlayerItem:self.playerItem];
    _playerLayer = [AVPlayerLayer playerLayerWithPlayer:self.moviePlayer];
    
    [self.playerLayer setFrame:frame];
    [self.moviePlayer seekToTime:kCMTimeZero];
    [self setPlayer:self.moviePlayer];
    [self setVideoFillMode:AVLayerVideoGravityResizeAspect];
    self.contentURL = nil;
    
    [self registerObserver];
    [self initializePlayerAtFrame];
    [self setupConstraints];
    [self showHUD:NO];
    [self showLoader:YES];
}

- (void)setFrame:(CGRect)frame
{
    [super setFrame:frame];
}

#pragma mark - 播放器UI定制
- (void)initializePlayerAtFrame
{
    self.backgroundColor = [UIColor blackColor];
    self.isViewShowing = NO;
    self.layer.masksToBounds = YES;
    

    // 整页蒙板
    self.overHudView = [[UIView alloc] init];
    [self addSubview:self.overHudView];

//////////////////////////////////////////////////////////////

    // 顶部工具栏
    self.toolsHUDView = [[UIView alloc] init];
    [self addSubview:self.toolsHUDView];
    
    // 顶部工具栏--返回按钮
    self.pageBackButton = [UIButton buttonWithType:UIButtonTypeCustom];
    // 点击按钮会有高光效果
    self.pageBackButton.showsTouchWhenHighlighted = YES;
    [self.pageBackButton setImage:[UIImage imageNamed:@"btn_back_normal"] forState:UIControlStateNormal];
    [self.pageBackButton addTarget:self action:@selector(pageBackButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self.toolsHUDView addSubview:self.pageBackButton];

    // 顶部工具栏--视频名标题 label
    self.titleLabel = [[UILabel alloc] init];
    self.titleLabel.textAlignment = NSTextAlignmentLeft;
    self.titleLabel.textColor = [UIColor whiteColor];
    self.titleLabel.font      = Font_ChinaBold(15);
    [self.titleLabel sizeToFit];
    [self.toolsHUDView addSubview:self.titleLabel];

//////////////////////////////////////////////////////////////

    // 开始暂停按钮
    self.playPauseButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    self.playPauseButton.showsTouchWhenHighlighted = YES;//选中高光
    self.playPauseButton.layer.opacity = 0;
    self.playPauseButton.selected = NO;
    self.playPauseButton.tintColor = [UIColor clearColor];
    [self.playPauseButton setBackgroundImage:[UIImage imageNamed:@"btn_play"] forState:UIControlStateNormal];
    [self.playPauseButton setBackgroundImage:[UIImage imageNamed:@"btn_play"] forState:UIControlStateHighlighted];
    [self.playPauseButton setBackgroundImage:[UIImage imageNamed:@"btn_pause"] forState:UIControlStateSelected];
    
    [self.playPauseButton addTarget:self action:@selector(playButtonAction:) forControlEvents:UIControlEventTouchUpInside];
    [self addSubview:self.playPauseButton];

//////////////////////////////////////////////////////////////
    
    // 底部工具栏
    self.playerHudView = [[UIView alloc] init];
    [self addSubview:self.playerHudView];
    
    // 底部工具栏--时间进度条
    self.progressBar = [[UISlider alloc] init];
    [self.progressBar setThumbImage:[UIImage imageNamed:@"progress_controller"] forState:UIControlStateNormal];
    self.progressBar.maximumTrackTintColor = [UIColor clearColor];
    [self.progressBar addTarget:self action:@selector(progressBarChanged:) forControlEvents:UIControlEventValueChanged];
    [self.progressBar addTarget:self action:@selector(progressBarChangeEnded:) forControlEvents:UIControlEventTouchUpInside];
    [self.playerHudView addSubview:self.progressBar];
    
    // 缓冲进度条
    self.loadedTimeView = [[UIProgressView alloc] init];
    self.loadedTimeView.progressTintColor = [UIColor whiteColor];
    self.loadedTimeView.trackTintColor = [UIColor clearColor];
    [self.playerHudView addSubview:self.loadedTimeView];
    
    // 当前时长
    self.playBackTime = [[UILabel alloc] init];
    self.playBackTime.text = [self getStringFromCMTime:self.moviePlayer.currentTime];
    self.playBackTime.textAlignment = NSTextAlignmentLeft;
    self.playBackTime.textColor = [UIColor whiteColor];
    self.playBackTime.font = Font_China(12);
    [self.playBackTime sizeToFit];
    [self.playerHudView addSubview:self.playBackTime];
    
    // 总时长
    self.playBackTotalTime = [[UILabel alloc] init];
    self.playBackTotalTime.text = [ self getStringFromCMTime:self.moviePlayer.currentItem.asset.duration];
    self.playBackTotalTime.textAlignment = NSTextAlignmentRight;
    self.playBackTotalTime.textColor = [UIColor whiteColor];
    self.playBackTotalTime.font = Font_China(12);
    [self.playBackTotalTime sizeToFit];
    [self.playerHudView addSubview:self.playBackTotalTime];
    
//////////////////////////////////////////////////////////////

    CMTime interval = CMTimeMake(33, 100);
    __weak typeof(self) weakSelf = self;
    
    _playbackObserver = [self.moviePlayer addPeriodicTimeObserverForInterval:interval queue:dispatch_get_main_queue() usingBlock:^(CMTime time) {
        
        CMTime endTime = CMTimeConvertScale(weakSelf.moviePlayer.currentItem.asset.duration, weakSelf.moviePlayer.currentTime.timescale, kCMTimeRoundingMethod_RoundHalfAwayFromZero);
        
        if(CMTimeCompare(endTime, kCMTimeZero) != 0)
        {
            double normalizedTime = (double)weakSelf.moviePlayer.currentTime.value / (double)endTime.value;
            weakSelf.progressBar.value = normalizedTime;
        }
        
        weakSelf.playBackTime.text = [weakSelf getStringFromCMTime:weakSelf.moviePlayer.currentTime];
    }];

}

- (void)setupConstraints
{
    // 整页蒙板
    [self.overHudView mas_makeConstraints:^(MASConstraintMaker *make) {

        // 直接用size铺满怎么页面
        make.size.equalTo(self);
    }];

    // 顶部工具栏
    [self.toolsHUDView mas_makeConstraints:^(MASConstraintMaker *make) {
       
        // 设置上左右约束，再设置高度
        make.left.equalTo(self.left);
        make.right.equalTo(self.right);
        make.height.equalTo(ToolsHudH);
    }];
    
    // 顶部工具栏内部
    // 返回按钮
    [self.pageBackButton mas_makeConstraints:^(MASConstraintMaker *make) {
       
        make.width.equalTo(30);
        make.height.equalTo(30);
        make.left.equalTo(self.left).offset(10);
        make.centerY.equalTo(self.toolsHUDView.centerY);
        make.right.equalTo(self.titleLabel.left).offset(-10);
    }];
    
    // 标题
    [self.titleLabel mas_makeConstraints:^(MASConstraintMaker *make) {
        make.right.equalTo(self.toolsHUDView.right).offset(-10);
        make.height.equalTo(30);
        make.centerY.equalTo(self.toolsHUDView.centerY);
    }];

    // 播放暂停按钮
    [self.playPauseButton mas_makeConstraints:^(MASConstraintMaker *make) {
       
        
        make.width.equalTo(80);
        make.height.equalTo(80);
        make.centerX.equalTo(self.centerX);
        make.centerY.equalTo(self.centerY);
    }];

    // 底部工具条
    [self.playerHudView mas_makeConstraints:^(MASConstraintMaker *make) {
       
        make.height.equalTo(PlayHudH);
        make.left.equalTo(self.left);
        make.right.equalTo(self.right);
        make.bottom.equalTo(self.bottom);
    }];
    
    // 底布工具条内部
    // 播放时间
    [self.playBackTime mas_makeConstraints:^(MASConstraintMaker *make) {
       
        make.height.equalTo(self.playerHudView.height);
        make.left.equalTo(self).offset(20);
        make.centerY.equalTo(self.playerHudView.centerY);
        make.right.equalTo(self.progressBar.left).offset(-20);
    }];
    
    // 缓存进度条
    [self.loadedTimeView mas_makeConstraints:^(MASConstraintMaker *make) {
        
        make.left.equalTo(self.progressBar.left);
        make.right.equalTo(self.progressBar.right);
        make.top.equalTo(self.progressBar.top);
        make.bottom.equalTo(self.progressBar.bottom);
    }];
    
    // 进度条
    [self.progressBar mas_makeConstraints:^(MASConstraintMaker *make) {
       
        make.centerY.equalTo(self.playerHudView.centerY);
        make.height.equalTo(3);
        make.right.equalTo(self.playBackTotalTime.left).offset(-20);
    }];
    
    // 剩余时间
    [self.playBackTotalTime mas_makeConstraints:^(MASConstraintMaker *make) {
       
        make.centerY.equalTo(self.playerHudView.centerY);
        make.right.equalTo(self.right).equalTo(-20);
        make.height.equalTo(self.playerHudView.height);
    }];

}


#pragma mark - 屏幕触摸事件
- (void)touchesEnded:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    CGPoint point = [(UITouch *)[touches anyObject] locationInView:self];
    if(CGRectContainsPoint(self.playerLayer.frame, point))
    {
        [self showHUD:!self.isViewShowing];
    }
}

- (void)showHUD:(BOOL)show
{
    __weak typeof(self) weakSelf = self;
    if (show) {
        
        self.overHudView.hidden = NO;
        
        [UIView animateWithDuration:0.3 animations:^{
            weakSelf.playerHudView.my_y = weakSelf.my_Height - weakSelf.playerHudView.my_Height;
            weakSelf.toolsHUDView.my_y = weakSelf.my_y;
            
            weakSelf.playPauseButton.layer.opacity = 1;
            self.isViewShowing = show;
        }];
    }
    else
    {
        self.overHudView.hidden = YES;
        
        [UIView animateWithDuration:0.3 animations:^{
            weakSelf.toolsHUDView.my_y = weakSelf.my_y - weakSelf.toolsHUDView.my_Height;
            weakSelf.playerHudView.my_y = self.my_Height;
            weakSelf.playPauseButton.layer.opacity = 0;
            self.isViewShowing = show;
        }];
        
    }
    
    if(self.shouldShowHideParentNavigationBar)
    {
        if (UIInterfaceOrientationIsPortrait([UIDevice currentDevice].orientation)) {
            [[self superviewNavigationController] setNavigationBarHidden:_isViewShowing animated:YES];
        }
    }
}

#pragma mark - 页面点击事件
- (void)playerFinishedPlaying
{
    [self.moviePlayer pause];
    [self.moviePlayer seekToTime:kCMTimeZero];
    [self.playPauseButton setSelected:NO];
    self.isPlaying = NO;
    if([self.delegate respondsToSelector:@selector(playerFinishedPlayback:)])
    {
        [self.delegate playerFinishedPlayback:self];
    }
}

- (UINavigationController *)superviewNavigationController
{
    for (UIView *next = [self superview]; next; next = next.superview) {
        UIResponder *nextResponder = [next nextResponder];
        
        if([nextResponder isKindOfClass:[UINavigationController class]])
        {
            return (UINavigationController *)nextResponder;
        }
    }
    return nil;
}

#pragma mark - 时间遍历方法
- (NSString *)getStringFromCMTime:(CMTime)time
{
    Float64 currentSeconds = CMTimeGetSeconds(time);
    int mins = currentSeconds / 60.0;
    int secs = fmodf(currentSeconds, 60.0);
    
    NSString *minsString = mins < 10 ? [NSString stringWithFormat:@"0%d",mins] : [NSString stringWithFormat:@"%d",mins];
    
    NSString *secsString = secs < 10 ? [NSString stringWithFormat:@"0%d",secs] : [NSString stringWithFormat:@"%d",secs];
    
    return [NSString stringWithFormat:@"%@:%@",minsString,secsString];
}

#pragma mark - pageBack 按钮动作
- (void)pageBackButtonAction:(UIButton *)sender
{
    WYLog(@"页面返回");
    
    if([self.delegate respondsToSelector:@selector(pageBackButtonAction)])
    {
        [self.delegate pageBackButtonAction];
    }
}

#pragma mark - play / pause 按钮动作
- (void)playButtonAction:(UIButton *)sender
{
    if(self.isPlaying)
    {
        [self pause];
    }
    else
    {
        [self play];
    }
}

#pragma mark - ProgressBar change handling

- (void)progressBarChanged:(UISlider *)sender
{
    if(self.isPlaying)
    {
        [self.moviePlayer pause];
    }
    
    CMTime seekTime = CMTimeMakeWithSeconds(sender.value * (double)self.moviePlayer.currentItem.asset.duration.value / (double)self.moviePlayer.currentItem.asset.duration.timescale, self.moviePlayer.currentTime.timescale);
    [self.moviePlayer seekToTime:seekTime];
}

- (void)progressBarChangeEnded:(UISlider *)sender
{
    if(self.isPlaying)
    {
        [self.moviePlayer play];
    }
}

- (void)play
{
    [self.moviePlayer play];
    self.isPlaying = YES;
    [self.playPauseButton setSelected:YES];
    [self showHUD:!self.isViewShowing];
}

- (void)pause
{
    [self.moviePlayer pause];
    self.isPlaying = NO;
    [self.playPauseButton setSelected:NO];
}

- (void)endPlayer
{
    [self.moviePlayer pause];
    self.moviePlayer.rate = 0.0;
    self.isPlaying = NO;
    [self.playerLayer removeFromSuperlayer];
    self.moviePlayer = nil;
}



#pragma mark - Audio/vibrate override
- (void)setShouldPlayAudioOnVibrate:(BOOL)shouldPlayAudioOnVibrate
{
    _shouldPlayAudioOnVibrate = shouldPlayAudioOnVibrate;
    
    NSError *error = nil;
    
    if(shouldPlayAudioOnVibrate)
    {
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
        
        [[AVAudioSession sharedInstance] setActive:YES error:&error];
    }
    else
    {
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayback error:&error];
        
        [[AVAudioSession sharedInstance] setActive:NO error:&error];
    }
    
    if(error)
    {
        WYLog(@"%s: error while setting audio vibrate overwrite - %@", __func__, [error localizedDescription]);
    }
}

#pragma mark - ActivityIndicator show/hide
- (void)showLoader:(BOOL)wasInterrupted
{
    if(!self.activityIndicator)
    {
        _activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
        
        [self.activityIndicator startAnimating];
        
        self.activityIndicator.translatesAutoresizingMaskIntoConstraints = NO;
        [self addSubview:self.activityIndicator];
        
        [self bringSubviewToFront:self.playPauseButton];
        
        if(!wasInterrupted)
        {
            self.playPauseButton.alpha = 0.0;
        }
        
        [self.activityIndicator mas_makeConstraints:^(MASConstraintMaker *make) {
            make.centerX.equalTo(self.centerX);
            make.centerY.equalTo(self.centerY);
            make.width.equalTo(30);
            make.height.equalTo(30);
        }];
    }
}

- (void)removeLoader
{
    [UIView animateWithDuration:0.5 animations:^{
        self.playPauseButton.alpha = 1.0;
        self.activityIndicator.alpha = 1.0;
    } completion:^(BOOL finished) {
        [self.activityIndicator stopAnimating];
        [self.activityIndicator removeFromSuperview];
        self.activityIndicator = nil;
    }];
}

#pragma mark - Observer handling for player playerItem
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
    if([object isKindOfClass:[AVPlayerItem class]])
    {
        AVPlayerItem *item = (AVPlayerItem *)object;
        
        if([keyPath isEqualToString:@"status"])
        {
            switch (item.status)
            {
                case AVPlayerItemStatusFailed:
                    [SVProgressHUD showErrorWithStatus:@"网络错误"];
                    WYLog(@"%s: player item status failed",__func__);
                    break;
                    
                case AVPlayerItemStatusReadyToPlay:
                    WYLog(@"%s: player item status is ready to play" , __func__);
                    [self removeLoader];
                    [self play];
                    break;
                    
                case AVPlayerItemStatusUnknown:
                    WYLog(@"%s: player item status is unknown",__func__);
                    break;
                default:
                    break;
            }
        }
        else if ([keyPath isEqualToString:@"loadedTimeRanges"])
        {
            NSTimeInterval timeInterval = [self availableDuration];
            CMTime duration = self.playerItem.duration;
            
            CGFloat totalDuration = CMTimeGetSeconds(duration);
            
            [self.loadedTimeView setProgress:timeInterval / totalDuration animated:YES];
            WYLog(@"loadedTimeRanges %f" , (timeInterval / totalDuration));
        }
        else if ([keyPath isEqualToString:@"playbackBufferEmpty"])
        {
            if(item.playbackBufferEmpty)
            {
                if(!item.isPlaybackBufferEmpty && !item.isPlaybackBufferFull)
                {
                    if(self.moviePlayer.rate == 0.0)
                    {
                        [self showLoader:YES];
                        [self pause];
                    }
                    
                }
                WYLog(@"%s: player item playback buffer is empty",__func__);
            }
        }
    }
    
    if([object isKindOfClass:[AVPlayer class]])
    {
        if([keyPath isEqual:@"rate"])
        {
            CGFloat frameRate = [(AVPlayer *)object rate];
            
            if(frameRate > 0.0 && self.activityIndicator)
            {
                [self removeLoader];
            }
            else if (frameRate < 0.0 && self.activityIndicator == nil)
            {
                [self showLoader:YES];
            }
            WYLog(@"%s: player rate is %f" , __func__ , [(AVPlayer *)object rate]);
        }
    }
}

#pragma mark - availableDuration

- (NSTimeInterval)availableDuration
{
    NSArray *loadedTimeRanges = [[self.moviePlayer currentItem] loadedTimeRanges];
    CMTimeRange timeRange = [loadedTimeRanges.firstObject CMTimeRangeValue];
    
    float startSeconds = CMTimeGetSeconds(timeRange.start);
    float durationSecond = CMTimeGetSeconds(timeRange.duration);
    
    NSTimeInterval result = startSeconds + durationSecond;
    
    return result;
}


#pragma mark - KVO of Player notifications setup / teardown
- (void)registerObserver
{
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playerFinishedPlaying) name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem];
    
    for (NSString *keyPath in [self observablePlayerItemKeyPaths]) {
        [self.playerItem addObserver:self forKeyPath:keyPath options:0 context:NULL];
    }
    
    [self.player addObserver:self forKeyPath:@"rate" options:0 context:NULL];
}

- (void)unregisterObservers
{
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    
    for (NSString *keyPath  in [self observablePlayerItemKeyPaths])
    {
        [self.playerItem removeObserver:self forKeyPath:keyPath];
    }
    
    [self.player removeObserver:self forKeyPath:@"rate"];
}

- (NSArray *)observablePlayerItemKeyPaths
{
    return [NSArray arrayWithObjects:@"playbackBufferEmpty",@"status",@"loadedTimeRanges", nil];
}

- (void)setTitleName:(NSString *)titleName
{
    if(titleName)
    {
        _titleName = titleName;
        self.titleLabel.text = titleName;
    }
}

#pragma mark - 销毁
- (void)dealloc
{
    [self.moviePlayer removeTimeObserver:self.playbackObserver];
    [self unregisterObservers];
    
    self.playerItem = nil;
    self.playerLayer = nil;
    self.activityIndicator = nil;
    self.playbackObserver = nil;
}

@end
